*******************************************************************************
* Math
*
* (C)  Copyright Apple Computer, Inc. 1988
* All rights reserved.
*
* by Jim Mensch
* 7/14/88
*
* Sample to show how to use the Integer math and SANE tools. This program shows
* 2 basic operations performed both with the integer math tools and SANE. The
* first is the calculation and display of a simple SINE curve. The second is
* a more complex Fast Fourier Transform.
*
* Files:	System macros and equates
*
*
*
* Modification History:
*
* Version 1.0	Mensch
*
*      7/14/88
*
*      Initial release
*
*******************************************************************************
	eject
	
**********************************************************************
*                                                                    *
*             Apple IIGS Source Code Sampler, Volume I               *
*                                                                    *
*             Copyright (c) Apple Computer, Inc. 1988                *
*                       All Rights Reserved                          *
*                                                                    *
*            Written by Apple II Developer Tech Support              *
*                                                                    *
*                                                                    *
*                                                                    *
*  ----------------------------------------------------------------  *
*                                                                    *
*     This program and its derivatives are licensed only for         *
*     use on Apple computers.                                        *
*                                                                    *
*     Works based on this program must contain and                   *
*     conspicuously display this notice.                             *
*                                                                    *
*     This software is provided for your evaluation and to           *
*     assist you in developing software for the Apple IIGS           *
*     computer.                                                      *
*                                                                    *
*     DISCLAIMER OF WARRANTY                                         *
*                                                                    *
*     THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                       *
*     WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,               *
*     WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
*     FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
*     THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH            *
*     YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND            *
*     NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)               *
*     ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,             *
*     REPAIR OR CORRECTION.                                          *
*                                                                    *
*     Apple does not warrant that the functions                      *
*     contained in the Software will meet your requirements          *
*     or that the operation of the Software will be                  *
*     uninterrupted or error free or that defects in the             *
*     Software will be corrected.                                    *
*                                                                    *
*     SOME STATES DO NOT ALLOW THE EXCLUSION                         *
*     OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY              *
*     NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC            *
*     LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS                *
*     WHICH VARY FROM STATE TO STATE.                                *
*                                                                    *
*                                                                    *
**********************************************************************
	eject
	
	PRINT NOHDR,NOGEN
	STRING AsIS

	PRINT PUSH,OFF
	INCLUDE 'M16.Util'
	INCLUDE 'M16.ProDOS'
	INCLUDE 'M16.QUICKDRAW'
	Include 'E16.Quickdraw'
	INCLUDE 'M16.MEMORY'
	Include 'E16.Memory'
	INCLUDE 'M16.EVENT'
	INCLUDE 'M16.LOCATOR'
	INCLUDE 'M16.MISCTOOL'
	INCLUDE 'M16.TextTOOL'
	INCLUDE 'M16.Menu'
	INCLUDE 'M16.Control'
	Include 'E16.Window'
	INCLUDE 'M16.Window'
	INCLUDE 'M16.Dialog'
	Include 'E16.Dialog'
	INCLUDE 'M16.LineEdit'
	Include 'M16.List'
	INCLUDE 'M16.IntMath'
	INCLUDE 'M16.Scrap'
	INCLUDE 'M16.Desk'
	INCLUDE 'E16.SANE'
	INCLUDE 'M16.SANE'
	PRINT POP

DPHandle	equ 0
DPPointer	equ DPHandle+4
DeRef	equ DPPointer+4

ScreenWidth	equ 640
ScreenMode	equ $80

	EJECT
*******************************************************************************
*
* Math Macros
*
* Description:	The following macros are given to take care of some common
*	operations used when you are using SANE or IntMath.
*
*
*
*******************************************************************************

;------------------------------------------------------------------------------
;
; Copy and extended value from one variable to another
;
; ExtendEq SrcLoc,DestLoc - Copies 10 bytes from srcloc to DestLoc
;
;------------------------------------------------------------------------------
	MACRO
	ExtendEq &SrcLoc,&DestLoc
	lda &SrcLoc
	sta &DestLoc
	lda &SrcLoc+2
	sta &DestLoc+2
	lda &SrcLoc+4
	sta &DestLoc+4
	lda &SrcLoc+6
	sta &DestLoc+6
	lda &SrcLoc+8
	sta &DestLoc+8
	MEND
	
;-----------------------------------------------------------------------------
;
; Push a long space on the stack for fuction results
;
; LongResult
;
;-----------------------------------------------------------------------------
	MACRO
	LongResult
	pha
	pha
	EndM
	
;-----------------------------------------------------------------------------
;
; Store 0's into an Extended number
;
; STZEXT Dest - Stores 10 bytes of 0 into Dest
;
;------------------------------------------------------------------------------
	MACRO
	STZEXT &Dest
	stz &Dest
	stz &Dest+2
	stz &Dest+4
	stz &Dest+6
	stz &Dest+8
	EndM
	
;------------------------------------------------------------------------------
;
; Store 0's into a longword
;
; STZL Dest - stores 4 bytes of 0 into Dest
;
;------------------------------------------------------------------------------
	MACRO
	STZL &Dest
	stz &Dest
	stz &Dest+2
	EndM

	EJECT
*******************************************************************************
*
Math	PROC
*
* Description:	This main routine calls the other major routines in the 
*	correct order.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import QuitParms
	Import InitTools
	Import InitApp
	Import EventLoop
	Import CloseTools
	Import CloseApp
*
* Entry Points:	None
*
*******************************************************************************

	jsr InitTools
	jsr InitApp

	_ShowCursor

	jsr EventLoop
	jsr CloseApp
	jsr CloseTools

	_Quit QuitParms

	EndP

	EJECT
*******************************************************************************
*
Globals	RECORD
*
* Description:	Global data for use in all routines of this demo. This area
*	also contains the data used by StandardLib.aii	
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:
	export QuitParms	; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString	str 'Apple IIgs Integer Math/Sane demo'
AutString	str 'By Jim Mensch Apple DTS ©1988 Apple Computer'
VersString	str 'Version: 1.0'


MenuHeight	ds.B 2	; Stored height of menu bar
MyID	ds.B 2	; Application ID
MyDP	ds.B 2	; My direct page storage

QuitFlag	ds.B 2
QuitParms	dc.L 0	; Pathname of next app
	dc.W $00	; flags

EventRecord
EventWhat	ds.B 2
EventMessage	ds.B 4
EventWhen	ds.B 4
EventWhere	ds.B 4
EventModifiers	ds.B 2
TaskData	ds.B 4
TaskMask	dC.L $0000FFFF

	EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr	dc.l AppMenu
	dc.l FileMenu
MenuPtrLen	equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.



AppMenu	dc.B '$$@\N1',$0D
	dc.B '--About Math...\N256U',$00
	dc.B '.'
FileMenu	dc.B '$$  File\N2',$0D
	dc.B '--SANE Fast Fourier transform\N260',$00
	dc.B '--Integer Fast Fourier transform\N261',0
	dc.B '--Integer Sine wave\N258*Ii',$00
	dc.B '--SANE Sine wave\N259*SsV',$00
	dc.B '--Quit\N257*Qq',$00
	dc.B '.'

; Paramater block used to create the main window for display. All the
; graphing routines will use this window to draw into.

MyWindow	dc.W WindEnd-*	; size of paramBlock
	dc.W %0010000000100000 ; frame bits : alert, vis
	dc.L 0	; no title bar, no title...
	dc.L 0	; ref con 0
	dc.W 0,0,0,0	; zoomed rect
	dc.L 0	; color table = default
	dc.W 0,0	; scroll bar XY origin
	dc.W 0,0	; no scroll no max...
	dc.W 0,0	; No zooming...
	dc.W 0,0	; no scrolling
	dc.W 0,0	; no paging....
	dc.L 0	; no info bar, no ref con
	dc.W 0	; info bar height (	none...)
	dc.L 0	; Frame defproc, NIL=standard
	dc.L 0	; no info bar def proc
	dc.L 0	; no auto updates..	(yet)
	dc.W 20,20,195,619	; bounds rect...
	dc.L $FFFFFFFF	; plane= on top...
	dc.L 0	; NIL storage pointer
WindEnd	equ *
ContRect	dc.W 0,0,180,599	; content rectangle

WindPointer	ds.B 4

; Constants used thru the program both represent PI*2

twoPi	dc.b $1D,$72,$33,$DC,$80,$CF,$0F,$C9,$01,$40
twoPiFix	dc.W $487E,$0006

; Titles for the bottom of the window

IntSineTitle	str 'Integer Math Demo: plotting Y=SIN(X)'
SANESineTitle	str 'SANE Demo: plotting Y=SIN(X)'
IntHarmTitle	str 'Integer Math Demo: plotting complex waveform'
SANEHarmTitle	str 'SANE Demo: plotting complex waveform'
	EndR
	
	EJECT
*******************************************************************************
*
InitApp	PROC
*
* Description:	This routine creates our window and zeros out the quitflag
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	Stz QuitFlag	; zero out quit flag

	PushLong #0
	PushLong #MyWindow
	_NewWindow	; create a window to graph in
	PullLong WindPointer

	PushLong WindPointer
	_SetPort	; make the new window the current port

	rts
	EndP

	EJECT
*******************************************************************************
*
CloseApp	PROC
*
* Description:	This routine will be called at program end to dispose of
*	the window.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	PushLong WindPointer
	_CloseWindow

	rts
	EndP

	EJECT
*******************************************************************************
*
EventLoop	PROC
*
* Description:	Main loop. Handles events until the user selects quit
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import Ignore
	Import MenuSelect
*
* Entry Points:
*
*******************************************************************************
	With Globals


	pha	; Push on space for TaskMaster result
	PushWord #$FFFF	; GetNextEvent mask
	PushLong #EventRecord ; Pointer to Event Record
	_TaskMaster

	pla	; Get TaskMaster result
	beq EventLoop	; Remove if you want to use null events
	asl A	; Turn it into an index
	tax
	jsr (TaskTable,x)	; Call appropriate event handler

	lda QuitFlag	; Quit selected?
	beq EventLoop	; no - keep looping

	rts	; yes- leave the program


TaskTable	dc.W Ignore	; 0 Null
	dc.W Ignore	; 1 MouseDown
	dc.W Ignore	; 2 Mouse Up
	dc.W Ignore	; 3 KeyDown
	dc.W Ignore	; 4 Undefined
	dc.W Ignore	; 5 AutoKey
	dc.W Ignore	; 6 Update
	dc.W Ignore	; 7 undefined
	dc.W Ignore	; 8 activate
	dc.W Ignore	; 9 Switch
	dc.W Ignore	; 10 desk acc
	dc.W Ignore	; 11 device driver
	dc.W Ignore	; 12 ap
	dc.W Ignore	; 13 ap
	dc.W Ignore	; 14 ap
	dc.W Ignore	; 15 ap
	dc.W Ignore	; TASK 0 indesk
	dc.W MenuSelect	; TASK 1 in menuBar
	dc.W Ignore	; TASK 2 in system window
	dc.W Ignore	; TASK 3 in content
	dc.W Ignore	; TASK 4 in Drag
	dc.W Ignore	; TASK 5 in grow
	dc.W Ignore	; TASK 6 in goaway
	dc.W Ignore	; TASK 7 in zoom
	dc.W Ignore	; TASK 8 in info bar
	dc.W Ignore	; TASK 9 in special	menu
	dc.W Ignore	; TASK 10 in NDA
	dc.W Ignore	; TASK 11 in frame
	dc.W Ignore	; TASK 12 in drop	        

	EndP
	
	EJECT
*******************************************************************************
*
MenuSelect	PROC
*
* Description:	This routine is called when taskmaster returns a code
*	indicating that the user selected one of our menu options.
*	This routine will call whatever routine is indicated for
*	each menu action
*
*
* Inputs:	TaskData - menu selected by the user
*
* Outputs:	None
*
* External Refs:
	Import Ignore
	Import DoAbout
	Import DoQuit
	Import IntSinecurve
	Import SANESineCurve
	Import IntHarmWave
	Import SANEHarmWave
*
* Entry Points:
*
*******************************************************************************
	With Globals

	lda TaskData	; get the ID of the menu item selected
	sec	; adjust it to be between 0 and 5
	sbc #256
	asl a	; multiply it by 2
	tax	; and use it as an index into our jump
	jsr (menuTable,x)	; table.

MSDone
	PushWord #0	; menu action complete, unhilite the
	PushWord taskData+2	; selected menu to show we are done
	_HiLiteMenu

	rts	; and quit

MenuTable	dc.W DoAbout	; about shell...
	dc.W DoQuit	; quit selected
	dc.W IntSineCurve	; draw integer math	sine wave
	dc.W SANESineCurve	; draw sane sine wave
	dc.W SANEHarmWave
	dc.W IntHarmWave
	EndP

	EJECT
*******************************************************************************
*
DoQuit	PROC
*
* Description:	Sets the quit flag to inform the event loop that the user
*	wants to stop the program
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	lda #$FFFF
	sta QuitFlag
	rts
	EndP

*******************************************************************************
*
Ignore	PROC
*
* Description:	Called when the program gets an event or menu selection that
*	it does not want to handle
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	rts
	EndP

	EJECT
*******************************************************************************
*
IntSineCurve	PROC
*
* Description:	This routine will calculate a simple Sine curve and display
*	it graphically on the screen.	
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	PushLong #ContRect	; first, start with a clean screen
	_EraseRect	; by erasing the old screen

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	_MoveTo
	
	PushLong #IntSineTitle
	_DrawString
	
	stzL LoopCount	; zero the counter to start this thing

	PushWord #0	; start this drawing off
	PushWord #80
	_MoveTo


DIMLoop
	LongResult	; space for results	here for all the
	LongResult	; following calculations. by pushing
	LongResult	; the space here, we do not need to 
	LongResult	; adjust the stack between int math calls
	LongResult	; and we save time and space
	
	PushLong LoopCount	; Calc: LoopCount/180
	PushLong One80	; 
	_FixDiv	; leave result on stack for next calc
		
	PushLong RFixPi	; Calc (LoopCount/180)*PI
	_FixMul	; to convert LoopCount to radians
	
	_fracSin	; take the sine of the counter
	
	_Frac2Fix	; convert it back to fixed #
	
	PushLong Eighty	; multiply it by 80 to scale
	_FixMul	; we have our number!
	PullLong YCord	; and its the y coordinate

	PushWord LoopCount+2 ; X coordinate (HiWord of Fixed)
	lda YCord+2	; Y coordinate + 80
	clc	; to scale the number between
	adc #80	; 0 and 160
	pha
	_LineTo	; draw the linesegment for this point

	inc LoopCount+2	; bump the loopcounter
	lda LoopCount+2	; and see if we have reached 360
	cmp #360	; for a full SINE curve
	bge DIMDone	; if so, then finish the loop
	brl DIMLoop	; if not do the next iteration
DIMDone
	rts	; finish the routine
LoopCount	ds.B 4	; Fixed number to store degrees
one80	dc.W 0,180	; a fixed number representing 180
Eighty	dc.W 0,80	; a FIxed number represenging 80
YCord	ds.B 4	; temp storage for the y coordinate
RFixPi	dc.L $0003243F	; 3.14159 (PI in fixed format)
	EndP

	EJECT
*******************************************************************************
*
SANESineCurve	PROC
*
* Description:	This routine will use the SANE toolset to calculate
*	a Sine curve. It will then plot the points on the screen.
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals

	PushLong #ContRect	; first, start with a clean screen
	_EraseRect	; by erasing the old screen

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	_MoveTo
	
	PushLong #SANESineTitle
	_DrawString
	
	PushWord #0	; start this drawing off
	PushWord #80	; in the middle of the screen
	_MoveTo
	
	stz LoopCount

DSaneLoop
	ExtendEq SanePi,TempResult ; move pi/180 into the result

	PushLong #LoopCount	; convert LoopCount to Radians
	PushLong #TempResult
	FMULI	; by multiplying by pi/180

	PushLong #TempResult
	FSINX	; now get the SINE of it

	PushLong #Eighty	; multiply by 80
	PushLong #TempResult
	FMULI

	PushLong #TempResult
	PushLong #YCord	; convert to an Integer
	FX2I

	PushWord LoopCount	; X coordinate
	lda YCord	; Y coordinate + 80
	clc	; to get a number between 
	adc #80	; 0 and 160
	pha
	_LineTo	; draw the line segement

	inc LoopCount	; bump the counter
	lda LoopCount
	cmp #360	; and see if we have done all 360 degrees
	bge DSaneDone	; if so then end
	brl DSaneLoop	; if not, get next value
DSaneDone
	rts
LoopCount	ds.B 4
SanePI	dc.B $AE,$C8,$E9,$94,$12,$35,$FA,$8E,$F9,$3F ; pi/180 ...
TempResult	ds.B 10
Eighty	dc.L 80
YCord	ds.B 4
	EndP


	EJECT
*******************************************************************************
*
FFTransData	Record
*
* Description:	Data used by both FFT calculation routines
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************

FixCount	dc.W 0	; fractional portsion of our
Count	ds.B 2	; fixed point counter
LoopCount	ds.B 2
FixSamp	dc.W 0	; fractional portion of the sample var
Sample	ds.B 2	; sample to figure for
FixMaxSamp	dc.W 0	; fractional portion of Max Sample
MaxSample	dc.W 256	; maximum number of	samples
MaxHarm	dc.W 6	; maximum number of harmonics
MaxValue	ds.B 10	; maximum vaule of the FFT
AmpTbl	dc.W 0,10,8,6,4,2,1	; amplitudes of each harmonic
PhaseTbl	dc.W 0,1,2,4,6,8,10	; high word of each fixed phase
PhaseTblF	dc.L 0,6554,13107,26214,39321,52428,$FFFF
TempValue	ds.B 10	; intermediate result storage
TempFactor	ds.B 10
Temp1	ds.B 10
Temp2	ds.B 10
FFTWave	ds.B 2560	; table to hold intermediate values
MyDecForm	dc.W 1
	dc.W 8	; 8 digits after the decimal place
TempI	ds.B 2
TempF	ds.B 4
Const127	dc.W 79
Const80Fix	dc.L $004F000
Const10	dc.W 10
	EndR


	EJECT
*******************************************************************************
*
SANEHarmWave	proc
*
* Description:	Create a complex harmonic wave using SANE
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import SaneFFTIteration
	Import DoNormI
*
* Entry Points:
*
*******************************************************************************

	With Globals
	With FFTransData

	PushLong #ContRect	; first, start with a clean screen
	_EraseRect	; by erasing the old screen

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	_MoveTo
	
	PushLong #SANEHarmTitle
	_DrawString
	

	PushWord #0	; start this drawing off
	PushWord #80	; at the left edge
	_MoveTo

	stz Sample	; and zero out all global values
	STZEXT MaxValue
	STZEXT temp1
	STZEXT temp2
	STZEXT tempFactor

DHWLoop1	jsr SaneFFTIteration ; do one iteration

	lda Sample	; now save tempValue into our array
	asl a	; multiply by 2
	sta Temp1	; and save it for a	sec
	asl a
	asl a	; multiply by 8
	clc
	adc Temp1	; x*8+x*2=x*10
	tax	; use as an index into the sample array

	lda TempValue	; now stow the current value
	sta FFTWave,x	; into our wave table. Later this
	lda TempValue+2	; table will be normalized
	sta FFTWave+2,x
	lda TempValue+4
	sta FFTWave+4,x
	lda TempValue+6
	sta FFTWave+6,x
	lda TempValue+8
	sta FFTWave+8,x

	inc Sample	; bump the sample counter
	lda #255
	cmp Sample	; test to see if we have reached the 
	bge DHWLoop1	; last sample, if not do the next one

; if the last sample was reached, it is time to go thru the wavetable and
; convert all the number so they are between 0 and 160.
	
	stz Count	; initialize the index
DHWLoop2	inc Count
	jsr DoNormI	; normalize one iteration

	PushWord Count	; X coordinate
	PushWord TempValue	; value returned by DoNormI
	_LineTo	; draw the line

	lda #255	; see if the counter has reached the max
	cmp Count	; sample we recorded
	bge DHWLoop2	; if not, do another point


	rts	; if it has, then we can simply end
	EndP
	
	EJECT
*******************************************************************************
*
SaneFFTIteration	PROC
*
* Description:	This routine takes the current sample value and computes
*	all the harmonic components that make up the wave for that
*	sample.
*
*
* Inputs:	Sample - current sample to compute for
*
* Outputs:	TempValue - output sample value
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	STZEXT TempValue

	PushLong #Sample
	PushLong #tempFactor
	FI2X	; convert the max sample rate to extended

	PushLong #MaxSample
	PushLong #Temp1
	FI2X

	PushLong #Temp1
	PushLong #tempFactor
	FDIVX	; tempFactor:=tempFactor/temp1

	PushLong #twoPi
	PushLong #TempFactor
	FMULX	; TempFactor:=6.28318*(count/maxSample)

	stz Count	; zero out the counter

FFLoop
	ExtendEq twoPi,Temp2

	lda Count	; get the count
	asl a	; multiply by 2
	tax
	lda PhaseTbl,x
	sta TempI
	PushLong #TempI
	PushLong #temp1
	FI2X	; Temp1:=Phase[count]

	PushLong #Const10
	PushLong #Temp1
	FDIVI	; divide by 10 to make it fractional

	PushLong #Temp1
	PushLong #Temp2
	FMulX	; temp2:=(temp1)/10*twoPi

	ExtendEq tempFactor,temp1

	PushLong #Count
	PushLong #Temp1
	FMULI	; tempi:=count*tempFactor

	PushLong #Temp2
	PushLong #Temp1
	FADDX	; temp1:=((count*tempFactor)+(6.28318*Phase[count]))

	PushLong #Temp1
	FCOSX	; temp1:=Cos(temp1)

	lda Count	; get the count
	asl a	; multiply by 2
	tax
	lda AmpTbl,x
	sta TempI
	PushLong #TempI
	PushLong #Temp1
	FMULI	; temp1:=temp1*Amp[count]

	PushLong #Temp1
	PushLong #TempValue
	FADDX	; finally tempValue:=tempValue+temp1

	PushLong #TempValue
	PushLong #Temp1
	FX2X	; copy tempvalue into temp1

	PushLong #Temp1
	FABSX

	PushLong #Temp1
	PushLong #MaxValue
	FCMPX	; now update the max value if needed

	FBLE FFTL010	; if the new number	<= old max ignore next line

	ExtendEq Temp1,MaxValue

FFTL010
	inc Count
	lda Count
	cmp MaxHarm	; are we done yet???
	bge FFTDone
	brl FFLoop
FFTDone	rts
	EndP

	EJECT
*******************************************************************************
*
DoNormI	Proc
*
* Description:	Normalize one iteration of the wavetable. This routine
*	takes the current sample value and converts it to 
*
*
* Inputs:	Count - current sample number
*
* Outputs:	TempValue - the normalized value
*
* External Refs:	None
*
* Entry Points:	None
*
*******************************************************************************
	With Globals
	With FFTransData

	lda Count
	asl a	; multiply by 2
	sta Temp1	; and save it for a	sec
	asl a
	asl a	; multiply by 8
	clc
	adc Temp1	; x*8+x*2=x*10
	tax

	lda FFTWave,x	; now load the current value
	sta TempValue
	lda FFTWave+2,x
	sta TempValue+2
	lda FFTWave+4,x
	sta TempValue+4
	lda FFTWave+6,x
	sta TempValue+6
	lda FFTWave+8,x
	sta TempValue+8

	ExtendEq MaxValue,temp2

	PushLong #Temp2
	PushLong #TempValue	; divide the two
	FDIVX

	PushLong #Const127	; now scale it
	PushLong #TempValue
	FMULI

	PushLong #Const127
	PushLong #TempValue
	FADDI

	PushLong #TempValue	; now, convert ot to an integer
	PushLong #TempI
	FX2I

	lda TempI
	sta TempValue
	rts
	EndP



	EJECT
*******************************************************************************
*
IntHarmWave	PROC
*
* Description:	This routine will create a complex waveformusing the 
*	integer math tools
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
	Import IntFFTIteration
	Import IntHarmI
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	PushLong #ContRect	; first, start with a clean screen
	_EraseRect	; by erasing the old screen

	PushWord #10	; label the bottom of the window
	PushWord #170	; to show what we are doing
	_MoveTo
	
	PushLong #IntHarmTitle
	_DrawString
	
	PushWord #0	; start this drawing off
	PushWord #80
	_MoveTo

	stz Sample	; zero out some starting values
	STZL MaxValue
	STZL temp1
	STZL temp2
	STZL tempFactor


DIWLoop1	jsr IntFFTIteration	; do one iteration of the wave

	lda Sample	; now save tempValue into our array
	asl a	; multiply by 2
	asl a
	tax

	lda TempValue	; now stow the temp	value
	sta FFTWave,x	; into an array for later use
	lda TempValue+2
	sta FFTWave+2,x

	inc Sample	; bump the sample counter
	lda #255	
	cmp Sample	; see if we are done
	bge DIWLoop1	; if not, get another sample

; Now that the array of values has been created. Go thru and scale
; each value so that it fits in our wave and is between 0 and 160

	stz Count	; zero the sample counter
DIWLoop2	inc Count
	jsr IntHarmI	; normalize one iteration

	PushWord Count	; X coordinate
	PushWord TempValue
	_LineTo	; draw the line

	lda #255
	cmp Count
	bge DIWLoop2

	rts
	EndP

	EJECT
*******************************************************************************
*
IntFFTIteration	PROC
*
* Description:	This routine will calculate one single iteration of the 
*	wave. It will add a the Cosine*amp of each desired
*	harmonic to create a single sample
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	stzL TempValue

	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	PushLong FixSamp	; sample fixed number format
	PushLong FixMaxSamp	; max sample fixed point number
	_FixDiv

	PushLong TwoPiFix
	_FixMul	; now multiply the two to get theFactor
	PullLong tempFactor


	stz Count	; zero out the counter

FFLoop

	lda Count	; get the count
	asl a	; multiply by 2
	asl a
	tax
	lda PhaseTblF,x
	sta TempF
	lda PhaseTblF+2,X
	sta TempF+2

	LongResult	 ; push room on the stack
	PushLong TwoPiFix
	PushLong TempF
	_FixMul	; temp2:=Phase(Count)*twoPi
	PullLong Temp2

	LongResult	 ; push room on the stack
	PushLong FixCount
	PushLong TempFactor
	_FixMul	; temp1:=count*tempFactor
	PullLong Temp1

	lda Temp1	; temp2:=temp1+temp2
	clc
	adc Temp2
	sta Temp2
	lda Temp1+2
	adc Temp2+2
	sta Temp2+2

	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	PushLong Temp2
	_FracCos	; temp2:=Cos(temp2)
	_Frac2Fix	; convert back to fixed!
	PullLong Temp2

	PushLong Temp2
	lda Count	; get the count
	asl a	; multiply by 2
	tax
	lda AmpTbl,x
	pha
	pea $0	; Low word of fixed	count
	_FixMul	; temp1:=temp1*Amp[count]
	PullLong Temp2

	lda TempValue	; now add it to tempValue
	clc
	adc Temp2
	sta TempValue
	sta Temp2
	lda TempValue+2
	adc Temp2+2
	sta TempValue+2	; Now test for max value
	sta Temp2+2
	bpl TestHigh	; number is positive, test for high
	lda #0	; Negate this number to get absolute value
	sec
	sbc Temp2	; negate this number
	sta Temp2
	lda #0
	sbc Temp2+2
	sta Temp2+2
TestHigh	lda Temp2+2
	cmp MaxValue+2	; is it bigger than	max value+2?
	beq FFTTestLow	; if equal test the	low byte
	bge FFTStoreMax	; if greater move it to high
	bra FFTL010
FFTTestLow	lda Temp2
	cmp MaxValue	; is it bigger?
	blt FFTL010
FFTStoreMax	lda Temp2+2
	sta MaxValue+2
	lda Temp2
	sta MaxValue

FFTL010
	inc Count
	lda Count
	cmp MaxHarm	; are we done yet???
	bge FFTDone
	brl FFLoop
FFTDone	rts
	EndP

	EJECT
*******************************************************************************
*
IntHarmI	PROC
*
* Description:	Takes an iteration of the wave divides it by the max value
*	and multiplies it by 160 to create a valid screen location
*
*
* Inputs:	None
*
* Outputs:	None
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
	With Globals
	With FFTransData

	lda Count
	asl a	; multiply by 4
	asl a
	tax
	lda FFTWave+2,x	; push current value on stack
	sta Temp1+2
	lda FFTWave,x	; 
	sta Temp1

	LongResult	 ; push room on the stack
	LongResult	 ; push room on the stack
	PushLong Temp1
	PushLong MaxValue	; divide it by maxvalue
	_FixDiv
	PullLong Temp2

	PushLong Temp2
	PushWord #$4F
	PushWord #0	; now scale it
	_FixMul
	PullLong Temp1

	lda Temp1+2
	clc
	adc #79
	sta TempValue
	rts
	EndP

	Include 'Math.Init.aii'

	END

